<html><head><base href="https://digikeys.com/"><title>DigiKeys - 18键电子琴模拟器（支持12音阶变调和和弦）</title>
<style>
body {
  font-family: Arial, sans-serif;
  background-color: #f0f0f0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  margin: 0;
}
.piano {
  background-color: #333;
  border-radius: 10px;
  padding: 20px;
  box-shadow: 0 0 20px rgba(0,0,0,0.3);
}
.keys {
  display: flex;
}
.key {
  width: 40px;
  height: 150px;
  background-color: white;
  border: 1px solid #333;
  margin: 0 2px;
  cursor: pointer;
  transition: background-color 0.1s;
}
.key.black {
  background-color: #333;
  height: 100px;
  width: 30px;
  margin-left: -15px;
  margin-right: -15px;
  z-index: 1;
}
.key.active {
  background-color: #ccc;
}
.key.black.active {
  background-color: #666;
}
.controls {
  margin-top: 20px;
  display: flex;
  justify-content: space-between;
  width: 100%;
}
select, button {
  padding: 5px 10px;
  font-size: 16px;
}
.chord-buttons {
  display: flex;
  justify-content: space-around;
  margin-top: 10px;
}
.chord-button {
  padding: 5px 10px;
  font-size: 16px;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.chord-button:hover {
  background-color: #45a049;
}
</style>
</head>
<body>
<h1>DigiKeys - 18键电子琴模拟器（支持12音阶变调和和弦）</h1>
<div class="piano">
  <div class="keys">
    <div class="key" data-note="C"></div>
    <div class="key black" data-note="C#"></div>
    <div class="key" data-note="D"></div>
    <div class="key black" data-note="D#"></div>
    <div class="key" data-note="E"></div>
    <div class="key" data-note="F"></div>
    <div class="key black" data-note="F#"></div>
    <div class="key" data-note="G"></div>
    <div class="key black" data-note="G#"></div>
    <div class="key" data-note="A"></div>
    <div class="key black" data-note="A#"></div>
    <div class="key" data-note="B"></div>
    <div class="key" data-note="C2"></div>
    <div class="key black" data-note="C#2"></div>
    <div class="key" data-note="D2"></div>
    <div class="key black" data-note="D#2"></div>
    <div class="key" data-note="E2"></div>
    <div class="key" data-note="F2"></div>
  </div>
  <div class="controls">
    <select id="instrument">
      <option value="sine">正弦波</option>
      <option value="square">方形波</option>
      <option value="sawtooth">锯齿波</option>
      <option value="triangle">三角波</option>
    </select>
    <select id="transpose">
      <option value="-6">降6半音</option>
      <option value="-5">降5半音</option>
      <option value="-4">降4半音</option>
      <option value="-3">降3半音</option>
      <option value="-2">降2半音</option>
      <option value="-1">降1半音</option>
      <option value="0" selected>原调</option>
      <option value="1">升1半音</option>
      <option value="2">升2半音</option>
      <option value="3">升3半音</option>
      <option value="4">升4半音</option>
      <option value="5">升5半音</option>
      <option value="6">升6半音</option>
    </select>
    <button id="record">录音</button>
    <button id="play" disabled>播放</button>
  </div>
  <div class="chord-buttons">
    <button class="chord-button" data-chord="C">C和弦 (1)</button>
    <button class="chord-button" data-chord="Dm7">Dm7和弦 (2)</button>
    <button class="chord-button" data-chord="E">E和弦 (3)</button>
    <button class="chord-button" data-chord="Fmaj7">Fmaj7和弦 (4)</button>
    <button class="chord-button" data-chord="G">G和弦 (5)</button>
    <button class="chord-button" data-chord="Am7">Am7和弦 (6)</button>
    <button class="chord-button" data-chord="Bm7">Bm7和弦 (7)</button>
  </div>
</div>

<script>
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const keys = document.querySelectorAll('.key');
const instrumentSelect = document.getElementById('instrument');
const transposeSelect = document.getElementById('transpose');
const recordButton = document.getElementById('record');
const playButton = document.getElementById('play');
const chordButtons = document.querySelectorAll('.chord-button');

let isRecording = false;
let recordedNotes = [];
let startTime;

const baseFrequencies = {
  'C': 261.63, 'C#': 277.18, 'D': 293.66, 'D#': 311.13, 'E': 329.63,
  'F': 349.23, 'F#': 369.99, 'G': 392.00, 'G#': 415.30, 'A': 440.00,
  'A#': 466.16, 'B': 493.88, 'C2': 523.25, 'C#2': 554.37, 'D2': 587.33,
  'D#2': 622.25, 'E2': 659.25, 'F2': 698.46
};

const chords = {
  'C': ['C', 'E', 'G'],
  'Dm7': ['D', 'F', 'A', 'C2'],
  'E': ['E', 'G#', 'B'],
  'Fmaj7': ['F', 'A', 'C2', 'E2'],
  'G': ['G', 'B', 'D2'],
  'Am7': ['A', 'C2', 'E2', 'G2'],
  'Bm7': ['B', 'D2', 'F#2', 'A2']
};

function getTransposedFrequency(note) {
  const semitones = parseInt(transposeSelect.value);
  const baseFreq = baseFrequencies[note];
  return baseFreq * Math.pow(2, semitones / 12);
}

function playNote(note) {
  const frequency = getTransposedFrequency(note);
  
  const oscillator = audioContext.createOscillator();
  const gainNode = audioContext.createGain();
  
  oscillator.type = instrumentSelect.value;
  oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime);
  
  gainNode.gain.setValueAtTime(0.7, audioContext.currentTime);
  gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 1);
  
  oscillator.connect(gainNode);
  gainNode.connect(audioContext.destination);
  
  oscillator.start();
  oscillator.stop(audioContext.currentTime + 1);
  
  if (isRecording) {
    const currentTime = Date.now() - startTime;
    recordedNotes.push({ note, time: currentTime });
  }
}

function playChord(chordName) {
  chords[chordName].forEach(note => {
    playNote(note);
    const key = document.querySelector(`[data-note="${note}"]`);
    if (key) {
      key.classList.add('active');
      setTimeout(() => key.classList.remove('active'), 300);
    }
  });
}

keys.forEach(key => {
  key.addEventListener('mousedown', () => {
    key.classList.add('active');
    playNote(key.dataset.note);
  });
  
  key.addEventListener('mouseup', () => {
    key.classList.remove('active');
  });
  
  key.addEventListener('mouseleave', () => {
    key.classList.remove('active');
  });
});

chordButtons.forEach(button => {
  button.addEventListener('click', () => {
    playChord(button.dataset.chord);
  });
});

recordButton.addEventListener('click', () => {
  if (!isRecording) {
    isRecording = true;
    recordedNotes = [];
    startTime = Date.now();
    recordButton.textContent = '停止录音';
    playButton.disabled = true;
  } else {
    isRecording = false;
    recordButton.textContent = '录音';
    playButton.disabled = false;
  }
});

playButton.addEventListener('click', () => {
  recordedNotes.forEach(note => {
    setTimeout(() => {
      playNote(note.note);
      const key = document.querySelector(`[data-note="${note.note}"]`);
      if (key) {
        key.classList.add('active');
        setTimeout(() => key.classList.remove('active'), 100);
      }
    }, note.time);
  });
});

document.addEventListener('keydown', (event) => {
  const keyMap = {
    'a': 'C', 'w': 'C#', 's': 'D', 'e': 'D#', 'd': 'E', 'f': 'F',
    't': 'F#', 'g': 'G', 'y': 'G#', 'h': 'A', 'u': 'A#', 'j': 'B',
    'k': 'C2', 'o': 'C#2', 'l': 'D2', 'p': 'D#2', ';': 'E2', "'": 'F2'
  };
  
  const chordKeyMap = {
    '1': 'C', '2': 'Dm7', '3': 'E', '4': 'Fmaj7', '5': 'G', '6': 'Am7', '7': 'Bm7'
  };
  
  const note = keyMap[event.key.toLowerCase()];
  const chord = chordKeyMap[event.key];
  
  if (note) {
    const key = document.querySelector(`[data-note="${note}"]`);
    if (key) {
      key.classList.add('active');
      playNote(note);
    }
  } else if (chord) {
    playChord(chord);
  }
});

document.addEventListener('keyup', (event) => {
  const keyMap = {
    'a': 'C', 'w': 'C#', 's': 'D', 'e': 'D#', 'd': 'E', 'f': 'F',
    't': 'F#', 'g': 'G', 'y': 'G#', 'h': 'A', 'u': 'A#', 'j': 'B',
    'k': 'C2', 'o': 'C#2', 'l': 'D2', 'p': 'D#2', ';': 'E2', "'": 'F2'
  };
  
  const note = keyMap[event.key.toLowerCase()];
  if (note) {
    const key = document.querySelector(`[data-note="${note}"]`);
    if (key) {
      key.classList.remove('active');
    }
  }
});
</script>

<footer style="margin-top: 20px; text-align: center;">
  <p>DigiKeys - 虚拟电子琴体验 | <a href="https://digikeys.com/about">关于我们</a> | <a href="https://digikeys.com/contact">联系我们</a></p>
  <p>探索更多音乐创作工具: <a href="https://digikeys.com/studio">DigiKeys Studio</a> | <a href="https://digikeys.com/learn">学习中心</a></p>
</footer>

</body></html>